package com.atguigu.gmall.realtime.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.atguigu.gmall.realtime.common.GmallConfig;
import org.apache.commons.lang3.StringUtils;
import org.apache.hadoop.hbase.client.Connection;
import redis.clients.jedis.Jedis;

/**
 * @author Felix
 * @date 2023/10/13
 * 使用旁路缓存的方式查询维度数据
 */
public class DimUtil {
    /**
     * 根据维度的主键获取维度数据
     * @param jedis         操作Redis的客户端
     * @param conn          连接hbase的客户端
     * @param nameSpace     hbase命名空间
     * @param tableName     表名
     * @param id            维度主键
     * @return
     * 优化：旁路缓存
     *      先从缓存中获取维度数据，如果在缓存中找到了要查询的维度，那么直接作为方法的返回值进行返回(缓存命中)；
     *      如果在缓存中没有找到要关联的维度，再发送请求到hbase中进行查询，并将查询的结果放到缓存中，
     *      方便下次查询使用。
     * 缓存产品选型：
     *      状态：     性能很好，维护性差
     *      Redis：   性能不错，维护性好      √
     * 关于Redis相关的设置
     *      key:    维度表表名:主键值   例如： dim_base_trademark:1
     *      类型：   String
     *      expire: 1day    避免冷数据常驻内存
     *      注意：如果维度数据发生了变化，将Redis中缓存的数据删除掉
     */
    public static JSONObject getDimInfo(Jedis jedis, Connection conn,String nameSpace,String tableName,String id){
        //拼接从Redis中查询的key
        String redisKey = tableName.toLowerCase() + ":" + id;

        //用于接收从Redis中查询的数据
        String dimStr = null;
        //用于接收方法的返回值
        JSONObject dimJsonObj = null;

        try {
            //先从缓存中获取维度数据
            dimStr = jedis.get(redisKey);
            if(StringUtils.isNotEmpty(dimStr)){
                System.out.println("~~~从Redis中查询到了对应"+tableName+"表中的"+id+"维度数据~~~");
                //如果在缓存中找到了要查询的维度，那么直接作为方法的返回值进行返回(缓存命中)
                dimJsonObj = JSON.parseObject(dimStr);
            }else{
                //如果在缓存中没有找到要关联的维度，再发送请求到hbase中进行查询
                //底层还是调用HbaseUtil工具类中getDimInfoFromHbase这个方法
                dimJsonObj = HbaseUtil.getDimInfoFromHbase(conn,nameSpace,tableName,id);
                if(dimJsonObj != null){
                    System.out.println("~~~从hbase中查询到了对应"+tableName+"表中的"+id+"维度数据~~~");
                    // 并将查询的结果放到缓存中
                    jedis.setex(redisKey,3600 * 24,dimJsonObj.toJSONString());
                }else{
                    System.out.println("~~~在Hbase中没有找到对应"+tableName+"表中的"+id+"维度数据~~~");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("~~~从Redis中查询维度数据发生了异常~~~");
        }
        return dimJsonObj;
    }

    public static void main(String[] args) {
        Jedis jedis = RedisUtil.getRedisClient();
        Connection conn = HbaseUtil.getHbaseConnection();
        System.out.println(getDimInfo(jedis, conn, GmallConfig.HBASE_NAMESPACE, "dim_base_trademark", "2"));
        RedisUtil.closeRedisClient(jedis);
        HbaseUtil.closeHbaseConnection(conn);
    }

    public static void deleteCache(String tableName,String id){
        String redisKey = tableName.toLowerCase() + ":" + id;
        Jedis jedis = null;
        try {
             jedis = RedisUtil.getRedisClient();
             jedis.del(redisKey);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if(jedis != null){
                System.out.println("~~~从Redis中清除缓存后，关闭Jedis~~~");
                jedis.close();
            }
        }
    }
}
